#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define CLOCK 3686400

#define INT_PER_SECOND ((CLOCK/256)/2)

char time_to_bcd(int value);

void EEPROM_write(unsigned int uiAddress, unsigned char ucData);
unsigned char EEPROM_read(unsigned int uiAddress);

int inc_seconds(void);
int inc_minutes(void);
int inc_hours(void);

unsigned int seconds = 0x00;
unsigned int minutes = 0x04;
unsigned int hours = 0x08;

int counter = 0;

int
main(void)
{
	char aux;
	char disp = 0xFE;

	/* Se setea el timer. */
	TCCR0 = (0 << WGM00)|(1 << WGM01)|(0 << CS00)|(0 << CS01)|(1 << CS02) ;

	/* Se setea el valor para comparar. */
	OCR0 = 1;

	/* Mascara de interrupciones. */
	TIMSK = (1 << OCIE0);

	/* Se inicializan los puertos de entrada y salida. */
	DDRD = 0xFF;
	DDRB = 0x00;

	/* Se habilitan las interrupciones. */
	sei();

	while(1) {
		aux = PINB;
		if (aux != 0xFF) {
			if (aux == 0xDF) {
				inc_seconds();
			}
			else if (aux == 0xBF) {
				inc_minutes();
			}
			else if (aux == 0x7F) {
				inc_hours();
			} else {
				disp = aux;
			}
		}
		if(disp == 0xFB) {
			PORTD = time_to_bcd(EEPROM_read(hours));
		} else if (disp == 0xFD) {
			PORTD = time_to_bcd(EEPROM_read(minutes));
		} else if (disp == 0xFE) {
			PORTD = time_to_bcd(EEPROM_read(seconds));
		}
		_delay_ms(300);
	}
}

/* Funcion para imprimir un entero entre 0 y 60 en formato BCD. */

char
time_to_bcd(int value)
{
	char izquierda = 0x00;
	char derecha = 0x00;
	if (value > 0 && value < 60) {
		if (value >= 10) {
			izquierda = value/10;
			izquierda = izquierda << 4;
		}
		derecha = value % 10;
	}
	return ~(izquierda | derecha);
}

/* Funciones para contar el tiempo. */

int inc_seconds(void)
{
	int carry = 0;
	unsigned char aux = EEPROM_read(seconds);
	aux = aux + 1;
	if (aux == 60) {
		aux = 0;
		carry = 1;
	}
	EEPROM_write(seconds, aux);
	return carry;
}

int inc_minutes(void)
{
	int carry = 0;
	unsigned char aux = EEPROM_read(minutes);
	aux = aux + 1;
	if (aux == 60) {
		aux = 0;
		carry = 1;
	}
	EEPROM_write(minutes, aux);
	return carry;
}

int inc_hours(void)
{
	int carry = 0;
	unsigned char aux = EEPROM_read(hours);
	aux = aux + 1;
	if (aux == 60) {
		aux = 0;
		carry = 1;
	}
	EEPROM_write(hours, aux);
	return carry;
}

ISR(TIMER0_COMP_vect)
{
	counter ++;
	if(counter == INT_PER_SECOND) {
		if(inc_seconds() == 1) {
			if(inc_minutes() == 1) {
				if(inc_hours()) {
					seconds = 0;
					minutes = 0;
				}
			}
		}
		counter = 0;
	}
}

void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
	/* Wait for completion of previous write. */

	while(EECR & (1<<EEWE)){
		;
	}

	/* Set up address and data registers. */

	EEAR = uiAddress; EEDR = ucData;

	/* Write logical one to EEMWE. */

	EECR |= (1<<EEMWE);

	/* Start eeprom write by setting EEWE. */

	EECR |= (1<<EEWE);
}

unsigned char EEPROM_read(unsigned int uiAddress)
{
	/* Wait for completion of previous write. */

	while(EECR & (1<<EEWE)){
		;
	}

	/* Set up address register. */

	EEAR = uiAddress;

	/* Start eeprom read by writing EERE. */

	EECR |= (1<<EERE);

	/* Return data from data register. */

	return EEDR;
}



